#include <iostream>
#include <string>
#include <vector>
#include <cstdlib>
#include <unistd.h>
#include <ctime>
#include "task.hpp"
#include <sys/types.h>
#include <sys/wait.h>

using namespace std;

enum
{
    UsageErr = 1,
    ArgErr,
    PipeErr
};

void Usage(const string& proc)
{
    cout << "Usage: " << proc << " subprocess - num" << endl;

}

class Channel
{
public:
    Channel(int wfd, pid_t sub_id, const string& name)
    :_wfd(wfd),_sub_process_id(sub_id),_name(name){}

    void PrintDebug()
    {
        cout << "_wfd:" << _wfd;
        cout << ", _sub_process_id:" << _sub_process_id;
        cout << ", _name:" << _name << endl;
    }

    string name(){ return _name; }

    int wfd(){ return _wfd; }

    pid_t pid(){ return _sub_process_id; }

    void Close() {close(_wfd);}

    ~Channel()
    {

    }
private:
    int _wfd;
    pid_t _sub_process_id;
    string _name; 
};

class ProcessPool
{
public:
   ProcessPool(int subprocess_num):_subprocess_num(subprocess_num){}

   int CerateProcess(work_t work)
   {
        vector<int> fds;
        for(int i = 0; i < _subprocess_num; i++)
        {
            int pipefd[2] = {0};
            int n = pipe(pipefd);
            if(n < 0) return PipeErr;

            pid_t id = fork();
            if(id == 0)
            {
                if(!fds.empty())
                {
                    for(auto fd: fds)
                    {
                        close(fd);
                    }
                }
                close(pipefd[1]);
                dup2(pipefd[0],0);//重定向
                work(pipefd[0]);
                exit(0);
            }
            string cnema = "channel-" + to_string(i);
            close(pipefd[0]);
            _Channels.push_back(Channel(pipefd[1],id,cnema));

            fds.push_back(pipefd[1]);
        }
        return 0;
    }

    int NextChannel()
    {
        static int next = 0;
        int c = next;
        next++;
        next %= _Channels.size();
        return c;
    }

    void SendTaskCode(int index, uint32_t code)
    {
        cout << "send code: " << code;
        cout << "to " << _Channels[index].name();
        cout << "sub process id: " << _Channels[index].pid() << endl;
        write(_Channels[index].wfd(), &code,sizeof(code));
    }

    void killall()
    {
        for(auto &e : _Channels)
        {
            e.Close();
            pid_t pid = e.pid();
            pid_t rid = waitpid(pid,nullptr,0);
            if(rid == pid)
            {
                cout << "wait sub process :" << pid << "sucess..." << endl;
            }
            cout << e.name() << " clsoe done" << " sub process quit now: " << e.pid() << endl;
        }
    }

    void Wait()
    {
        cout << "cheshi" <<endl;
        for(auto &Channel: _Channels)
        {
            // cout << "获取pid" <<endl;
            // pid_t pid = Channel.pid();
            // cout << "回收僵尸进程" <<endl;
            // pid_t rid = waitpid(pid,nullptr,0);
            // cout << "回收僵尸进程成功" <<endl;
            // if(rid == pid)
            // {
            //     cout << "wait sub process :" << pid << "sucess..." << endl;
            // }
        }
    }

    void Debug()
    {
        for(auto e:_Channels)
        {
            e.PrintDebug();
        }
    }

   ~ProcessPool()
   {


   } 
private:
    int _subprocess_num;
    vector<Channel> _Channels;
};

void CtrlProcessPool(ProcessPool* processpool_ptr,int cnt)
{
    while(cnt)
    {
        int target =  processpool_ptr->NextChannel();
        //sleep(1);
        //cout << target.name() << endl;

        uint32_t code = NextTask();

        processpool_ptr->SendTaskCode(target,code);
        sleep(1);
        cnt--;
    }
}

int main(int argc,char* argv[])
{
    if(argc != 2)
    {
        Usage(argv[0]);
        return UsageErr;
    }
    int subprocess_num = stoi(argv[1]);
    if(subprocess_num < 0) return ArgErr;

    srand((uint64_t)time(nullptr));

    //1.创建子进程
    ProcessPool* processpool_ptr = new ProcessPool(subprocess_num);
    processpool_ptr->CerateProcess(worker);
    processpool_ptr->Debug();

    //2.控制子进程
    CtrlProcessPool(processpool_ptr,2);

    cout << "task run done" <<endl;

    //sleep(100);
    //关闭进程
    processpool_ptr->killall();
    //processpool_ptr->Wait();

    delete processpool_ptr;
    return 0;
}

